package nio;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * description:
 * author:zt
 * date:2021-09-13
 */
public class NIOServer {
    public static void main(String[] args) throws Exception{
        //创建ServerSocketChannel -> ServerSocket
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //得到一个selector对象
        Selector selector = Selector.open();
        //绑定端口6666，在服务端监听
        serverSocketChannel.socket().bind(new InetSocketAddress(6666));
        //设置为非阻塞
        serverSocketChannel.configureBlocking(false);
        //将ServerSocketChannel注册到selector，关心事件为 连接
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        //循环等待客户端连接
        while (true){
            //等待一秒，如果没有事件发生，下一轮循环
            if (selector.select(1000) == 0){
                System.out.println("服务器等待1秒，无连接");
                continue;
            }

            //返回 >0 表示获取到了关注的事件
            //selector.selectedKeys()返回 发生了事件的所有selectionKey
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()){
                //获取到key 并判断发生的事件
                SelectionKey key = iterator.next();
                //如果是连接请求
                if (key.isAcceptable()){
                    SocketChannel socketChannel = serverSocketChannel.accept(); //此处为非阻塞，因为事件驱动，已经有accept请求才回到这里
                    socketChannel.configureBlocking(false);
                    System.out.println("客户端"+socketChannel.hashCode()+"已连接");
                    //将socketChannel注册到selector，关注事件为READ，同时关联一个buffer（在socketChannel和selector之间）
                    socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                }
                if (key.isReadable()){
                    //通过key 反向获取到对应的channel
                    SocketChannel channel = (SocketChannel) key.channel();
                    //获取到该channel关联的buffer 注册时注册的buffer（46行）
                    ByteBuffer buffer = (ByteBuffer) key.attachment();
                    channel.read(buffer); //将channel的消息读入到buffer
                    buffer.clear();
                    System.out.println("from 客户端：" + new String(buffer.array()));
                }
                //手动从集合中移除selectionKey，防止重复操作
                iterator.remove();
            }
        }
    }
}
